<?php

/**
 * MovableType PHP DAO is a project to help PHP developers to leverage the
 * database of MovableType, and wrap a data access layer around it, so you
 * can use object style to access it. This is very powerful if you want to
 * custimize MovableType and build new features around the data.
 *
 * Data layer, the only layer to directly deal with MySQL
 *
 * @version $Id$
 * @copyright 2007
 * @author Jian Shuo Wang <jianshuo@hotmail.com>
 */

class Data {

	// Below are the basic database configuration stuff
	private $table = null;
	private $columns = array();
	private $key = null;
	private $pkey = null;

	// There are uesd internally to store some temp data
	private $result = null;
	private $sql = null;
	private $connection = null;

	/**
	* $options contains the following parameters:
	*   'table' - the name of the table in the database
	* 	'key' - the key of the object that uniquely identify a row
	* 	'columns' - the array of the columns with objcol => dbcol format
	* 	'pkey' - optional parent key if it is the tree data structure
	*
	* This setup the database meta information for Data class to access database
	*
	*/
	function init($options){
		//init database columns
		foreach($options as $k => $v) {
			$this->$k = $v;
		}
		//init all the variables to null
		foreach($this->columns as $objcol => $dbcol) {
			$this->$objcol = null;
		}
	}

	/**
	* Load the object from database using the $id value
	* If $id is not specified, we will get it from the $key member varaible
	*
	*/
	function load($id = null){
		$key = $this->key;
		if(is_null($id)) {
			$id = $this->$key;
		}
		$columnStr = implode(', ', $this->columns);
		$this->sql = "SELECT $columnStr FROM {$this->table} WHERE {$this->columns[$key]} = '" . mysql_escape_string($id) . "'";
		if($this->query()) {
			$row = $this->fetch();
			foreach($this->columns as $objcol => $dbcol) {
				$this->$objcol = $row[$dbcol];
			}
		}
		return $this;
	}

	/**
	* Create a data object, and fill in the criteria to the member variables
	* Then find from the database using the non-null member variables.
	*
	*/
	function find($options = null){
		$columnStr = implode(',', $this->columns);
		$whereStr = " WHERE 1 = 1 ";
		$limitStr = " LIMIT 20 ";

		if(is_array($options) && array_key_exists('limit', $options)) {
			$limitStr = " LIMIT {$options['limit']}";
		}
		foreach($this->columns as $objcol => $dbcol) {
			if(!is_null($this->$objcol)) {
				$whereStr .= " AND $dbcol = '". mysql_escape_string($this->$objcol) ."'";
			}
		}
		$this->sql = "SELECT $columnStr FROM {$this->table} $whereStr $limitStr";
		if($this->query()) {
			$objs = array();
			while($row = $this->fetch()) {
				$obj = clone $this;
				$obj->reset();
				foreach($this->columns as $objcol => $dbcol)
					$obj->$objcol = $row[$dbcol];
				$objs[] = $obj;
			}
			return $objs;
		} else
			return array();
	}

	/**
	* The following two functions parent and children are only intended to
	* the tree structure like Category.
	*
	*/
	function parent(){
		if(is_set($this->pkey)) {
			$key = $this->key;
			$pkey = $this->pkey;

			$p = clone $this;
			$p->reset();
			$p->$key = $p->$pkey;
			$p->load();
			return $p;
		}
		return null;
	}

	function children(){
		if(isset($this->pkey)) {
			$key = $this->key;
			$pkey = $this->pkey;

			$o = clone $this;
			$o->reset();
			$o->$pkey = $this->$key;
			return $o->find();
		}
		return null;
	}

	private function query(){
		if(is_null($this->connection))
			$this->connection = DatabaseConnection::getConnection();
		$this->result = mysql_query($this->sql) or die(mysql_error());

		return mysql_num_rows($this->result);
	}

	private function fetch() {
		return mysql_fetch_assoc($this->result);
	}

	private function reset() {
		foreach($this->columns as $objcol => $dbcol)
			$this->$objcol = null;
	}
}

/**
* A singleton object to keep only one connection to the database in a page.
*
*/
class DatabaseConnection {
	static private $connection = null;

	static public function getConnection() {
		if(is_null(self::$connection)) {
			$cfg = self::config();
			self::$connection = mysql_connect($cfg['DBHost'], $cfg['DBUser'], $cfg['DBPassword']) or die ('I cannot connect to MySQL.');
			mysql_select_db($cfg['Database']);
		}

		return self::$connection;
	}

	static public function config() {
		$cfg = array();
		$file = '../mt-config.cgi';
		$cfg['DBPassword'] = '';
        if ($fp = file($file)) {
            foreach ($fp as $line) {
                // search through the file
                if (!ereg('^\s*\#',$line)) {
                    // ignore lines starting with the hash symbol
                    if (preg_match('/^\s*([^ ]+)[ ](.*)(\r|n)?$/', $line, $regs)) {
                        $key = trim($regs[1]);
                        $value = trim($regs[2]);
                        $cfg[$key] = $value;
                    }
                }
            }
        } else {
            die("Unable to open configuration file $file");
        }
		return $cfg;
	}

	static  function configFile() {
		echo getcwd();
		chdir('..');
		echo getcwd();
		//assert(file_exists('mt-config.cgi'));
	}
}
?>
